#ifndef __MCS__PROGRAM__HPP
#define __MCS__PROGRAM__HPP

#include "Object.hpp"
#include "Block.hpp"
#include "FunctionFactory.hpp"
#include <fstream>

/// The entire program object
class Program : public Object
{
public:
	Program(SourceLocation const & location, ptr<Element> elem, std::ostream * outputStream)
		: Object()
		, location_(location)
		, output_(*outputStream)
		, root_()
		, funcFactory_(new FunctionFactory())
	{
		FunctionCollection::registerCollections(funcFactory_.get());

		root_ = elem.dynamicCast<Block>();
		if(!root_)
		{
			root_ = new Block(location_);
			root_->appendElement(elem);
		}
		root_->initAsRoot(this);
	}

	/// Executes the program's body
	void execute()
	{
		root_->execute();
	}

	/// Returns reference to the stream that receives generated output.
	std::ostream & outputStream() { return output_; }

	/// Provides pointer to the function factory object.
	FunctionFactory * functionFactory() { return funcFactory_.get(); }
private:
	SourceLocation location_;
	std::ostream & output_;
	ptr<Block> root_;
	ptr<FunctionFactory> funcFactory_;
};

#endif //__MCS__PROGRAM__HPP